#include <assert.h>
#include <getopt.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <locale.h>

#include <vector>
#include <algorithm>

#include "slmbuilder.h"

static struct option long_options[] =
{
    {"ngram",    1, 0, 'n'},
    {"out",      1, 0, 'o'},
    {"cut",      1, 0, 'c'},
    {"discount", 1, 0, 'd'},
    {"wordcount",1, 0, 'w'},
    {"breakid",  1, 0, 'b'},
    {"excludeid",1, 0, 'e'},
    {"log",      1, 0, 'l'},
    {NULL,       0, 0, 0}
};

static void ShowUsage() {}

static int N = 0;
static CSlmBuilder builder;
static char* inputfilename = NULL;
static char* outfilename = NULL;
static std::vector<CSlmDiscounter *> discounter;

static void getParameters(int argc, char* argv[])
{
  int c = 0;
  char *ac = NULL, *cuts = NULL, *idstring = NULL, *dis_str = NULL;
	//char *idstr = NULL; 
  std::vector<TWORDID> ids;
  std::vector<CSlmBuilder::TFREQ> threshold;
  bool bUseLogPr = false;

  while ((c = getopt_long(argc, argv, "lw:n:c:d:o:b:e:", long_options, NULL))
         != -1) {
    int n, rmax, cut;
    double dis = 0;
    switch (c) {
    case 'l':
      bUseLogPr = true;
      break;
    case 'o':
      outfilename = strdup(optarg);
      break;
    case 'n':
      N = atoi(optarg);
      builder.Create(N);
      break;
    case 'w':
      n = atoi(optarg);
      builder.SetNumberOfWord(n);
      break;
    case 'c':
      cuts = strdup(optarg);
      ac = strtok(cuts, ",");
      while (ac != NULL) {
        cut = atoi(ac);
        threshold.push_back(CSlmBuilder::TFREQ(cut));
        ac = strtok(NULL, ",");
      }
      builder.SetCut(&(threshold[0]));
      free(cuts);
      break;
    case 'b':
      idstring = strdup(optarg);
      ac = strtok(idstring, ",");
      while (ac != NULL) {
        n = atoi(ac);
        ids.push_back(n);
        ac = strtok(NULL, ",");
      }
      builder.SetBreakerIds(ids.size(), &(ids[0]));
      free(idstring);
      break;
    case 'e':
    	idstring = strdup(optarg);
    	ac = strtok(idstring, ",");
    	while (ac != NULL) {
        n = atoi(ac);
			//n = atoi(optarg);
      	ids.push_back(n);
        ac = strtok(NULL, ",");
    	}
    	builder.SetExcludeIds(ids.size(), &(ids[0]));
    	free(idstring);
    	break;
    case 'd':
      dis_str = strdup(optarg);
      ac = strtok(dis_str, ",");
      if (strcmp(ac, "GT") == 0) {
        ac = strtok(NULL, ",");
        rmax = atoi(ac);
        ac = strtok(NULL, ",");
        dis = atof(ac);
        discounter.push_back(new CSlmGTDDiscounter(rmax, dis));
      } else if (strcmp(ac, "ABS") == 0) {
        if ((ac = strtok(NULL, ",")) != NULL)
          dis = atof(ac);
        discounter.push_back(new CSlmAbsoluteDiscounter(dis));
      } else if (strcmp(ac, "LIN") == 0) {
        if ((ac = strtok(NULL, ",")) != NULL)
          dis = atof(ac);
        discounter.push_back(new CSlmLinearDiscounter(dis));
      }
      break;
    default:
      ShowUsage();
    }
  }
  builder.SetUseLogPr(((bUseLogPr)?1:0));
  if (optind == argc -1) {
    inputfilename = strdup(argv[optind]);
    builder.SetDiscounter(&(discounter[0]));
  } else {
    fprintf(stderr, "Parameter input_file error\n");
    for (int i = optind; i < argc; ++i)
      fprintf(stderr, "%s ", argv[i]);
    fprintf(stderr, "\n");
    ShowUsage();
  }
}

int main(int argc, char* argv[]) {
  getParameters(argc, argv);

  TWORDID *ngram = new TWORDID[N+1];
  CSlmBuilder::TFREQ freq;

  printf("Reading and Processing raw idgram..."); fflush(stdout);
  FILE *fp = fopen(inputfilename , "rb");
  int nItems = 0;
  while (fread(ngram, sizeof(TWORDID), N, fp) == N &&
         fread(&freq, sizeof(freq), 1, fp) == 1) {
    builder.AddNGram(ngram, freq);
    ++nItems;
  }
  fclose(fp);
  delete ngram;
  printf("%d ngrams.\n", nItems); fflush(stdout);

  builder.Build();

  printf("\nWriting result file..."); fflush(stdout);
  FILE *out = fopen(outfilename, "wb");
  builder.Write(out);
  fclose(out);
  printf("\n"); fflush(stdout);

  return 0;
}
